import json
import os, sys, inspect, io
import time

import yaml
from transitions.extensions import HierarchicalMachine

cmd_folder = os.path.realpath(
    os.path.dirname(
        os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0])))

if cmd_folder not in sys.path:
    sys.path.insert(0, cmd_folder)

from transitions.extensions.states import Timeout, Tags, add_state_features
from transitions.extensions.factory import HierarchicalGraphMachine as Machine
from IPython.display import Image, display


@add_state_features(Timeout, Tags)
class CustomStateMachine(Machine):
    pass


class Matter(object):
    def do_x(self):
        pass

    def do_y(self):
        pass

    def do_z(self):
        pass

    def is_hot(self):
        return True

    def is_too_hot(self):
        return False

    def show_graph(self, **kwargs):
        stream = io.BytesIO()
        # self.get_graph(**kwargs).draw('my_state_diagram.png', prog='dot', format='png')
        self.get_graph(**kwargs).draw('svg_template.svg', prog='dot', format='svg')
        display(Image(stream.getvalue()))


extra_args = dict(auto_transitions=False, initial='standing', title='Mood Matrix',
                  show_conditions=True, show_state_attributes=True)

# %%

# states = [{'name': 'caffeinated', 'on_enter': 'do_x',
#            'children': ['dithering', 'running'], 'transitions': [['drink', 'dithering', '=']]},
#           {'name': 'standing', 'on_enter': ['do_x', 'do_y'], 'on_exit': 'do_z'},
#           {'name': 'walking', 'tags': ['accepted', 'pending'], 'timeout': 5, 'on_timeout': 'do_z'},
#
#           ]
# transitions = [
#     ['walk', 'standing', 'walking'],
#     ['哈哈哈', 'standing', 'walking'],
#     ['go', 'standing', 'walking'],
#     ['stop', 'walking', 'standing'],
#     {'trigger': 'drink', 'source': '*', 'dest': 'caffeinated_dithering',
#      'conditions': 'is_hot', 'unless': 'is_too_hot'},
#     ['walk', 'caffeinated_dithering', 'caffeinated_running'],
#     ['relax', 'caffeinated', 'standing'],
#     ['sip', 'standing', 'caffeinated']
# ]



states = ['A', 'B', {'name': 'C', 'parallel': [{'name': '1', 'children': ['a', 'b', 'c'], 'initial': 'a',
                                                'transitions': [['go', 'a', 'b']]},
                                               {'name': '2', 'children': ['x', 'y', 'z'], 'initial': 'z'}],
                      'transitions': [['go', '2_z', '2_x']]}]

transitions = [['reset', 'C_1_b', 'B']]
model = Matter()
machine = CustomStateMachine(model=model,states=states, transitions=transitions, initial='A')
model.to_C()
model.show_graph()
time.sleep(1)
# INFO:transitions.extensions.nesting:Exited state A
# INFO:transitions.extensions.nesting:Entered state C
# INFO:transitions.extensions.nesting:Entered state C_1
# INFO:transitions.extensions.nesting:Entered state C_2
# INFO:transitions.extensions.nesting:Entered state C_1_a
# INFO:transitions.extensions.nesting:Entered state C_2_z
model.go()
model.show_graph()
time.sleep(1)
# INFO:transitions.extensions.nesting:Exited state C_1_a
# INFO:transitions.extensions.nesting:Entered state C_1_b
# INFO:transitions.extensions.nesting:Exited state C_2_z
# INFO:transitions.extensions.nesting:Entered state C_2_x
model.reset()
model.show_graph()
time.sleep(1)
# INFO:transitions.extensions.nesting:Exited state C_1_b
# INFO:transitions.extensions.nesting:Exited state C_2_x
# INFO:transitions.extensions.nesting:Exited state C_1
# INFO:transitions.extensions.nesting:Exited state C_2
# INFO:transitions.extensions.nesting:Exited state C
# INFO:transitions.extensions.nesting:Entered state B


model = Matter()
machine = CustomStateMachine(model=model, states=states, transitions=transitions, **extra_args)
model.show_graph()
print(json.dumps(machine.markup, indent=4))
print(yaml.dump(machine.markup))
time.sleep(1)
# %%

model.walk()
model.show_graph()
time.sleep(1)
# %%

model.drink()
model.show_graph()
time.sleep(1)
# %%

model.walk()
model.show_graph()
time.sleep(1)
# %%

model.relax()
model.show_graph()
time.sleep(1)
# %%

model.show_graph(show_roi=True)
time.sleep(1)
# %%

# multimodel test
model1 = Matter()
model2 = Matter()
machine = CustomStateMachine(model=[model1, model2], states=states, transitions=transitions, **extra_args)
model1.drink()
model1.drink()
model2.walk()
model1.show_graph()
model2.show_graph()
